/*
 * COMP6471 Project1
 *  
 * This file is created by Yuan Tao (ewan.msn@gmail.com)
 * Licensed under GNU GPL v3
 * 
 * $Author: ewan.msn@gmail.com $
 * $Date: 2011-09-29 04:08:06 +0000 (Thu, 29 Sep 2011) $
 * $Rev: 19 $
 * $HeadURL: http://comp6471.googlecode.com/svn/Project1/src/kklib/InputLoader.java $
 * 
 */

package kklib;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.StringTokenizer;

import util.logger;

public class InputLoader {
	public static final int MAX_FILES = 50;
	
	// load one text file and store the data of file in the Layout objects.
	public int loadTextFile(String fileFullname, Layout layout) {
        String line;
        BufferedReader in;
        
		try {
			in = new BufferedReader(new FileReader(fileFullname));
	        line = in.readLine();        
	        while(line != null) {
	        	layout.txtFileData.add(line.toUpperCase());
	            line = in.readLine();
	        }
		} catch (FileNotFoundException e) {
			logger.err("File not found: " + fileFullname);
			return -1;
		} catch (IOException e) {
			e.printStackTrace();
			logger.err(e.getMessage());
			return -1;
		}
		
		layout.fileFullname = fileFullname;		// it indicates the file loaded successfully
		
		return 0;
	}
	
	// load all files under a directory
	public int loadTextFiles(String dirPath, ArrayList<Layout> layouts) {
        File filesDir = new File(dirPath);
        
        File list[] = filesDir.listFiles();
        if (list.length > MAX_FILES) {
			logger.output("Too many files under directory: " + dirPath);
			return -1;
		}
        
        for(int i=0;i<list.length;i++)
        {
            if(list[i].isFile())
            {
            	String fileFullname =dirPath + "\\" + list[i].getName(); 
            	logger.info(fileFullname);
            	
            	// load the file
            	Layout layout = new Layout();  // create the layout
            	if (loadTextFile(fileFullname, layout) != 0) {
					logger.output("Fail to load txt file: " + fileFullname);
					continue;
				}
                
                layouts.add(layout);
            }
        }
		return 0;
	}
	
	/* try to parse one line of the following format text.
	 	2 = 1 A1
		7 + 2 A2 A3
		2 - 2 A4 B4
		12 * 2 B1 C1
		3 + 2 B2 C2
		1 = 1 B3
		1 - 2 C3 D3
		2 / 2 C4 D4
		3 - 2 D1 D2
	 */
	private int cageParser(StringTokenizer st, Layout layout, String line) {
		int cnt = st.countTokens();
		
		if (cnt < 4) {
			logger.parserErr(layout.fileFullname, "Cannot parse cage from string: " + line);
			return -1;
		}
		
		// try to get the target number
		String str = st.nextToken();
		int targetNumber = 0;
		
		try {
			targetNumber = Integer.parseInt(str);
		} catch (NumberFormatException e) {
			logger.parserErr(layout.fileFullname, "Cannot get TargetNumber from string: " + line);
			return -1;
		}
		Cage cage = new Cage();		// create a new cage
		cage.targetNumber = targetNumber;

		// operator
		str = st.nextToken();
		if (str.equals("+")) {
			cage.operator = Cage.OP_ADD;
		} else if (str.equals("-")) {
			cage.operator = Cage.OP_SUB;
		} else if (str.equals("*")) {
			cage.operator = Cage.OP_MUL;
		} else if (str.equals("/")) {
			cage.operator = Cage.OP_DIV;
		} else if (str.equals("=")) {
			cage.operator = Cage.OP_EQU;
		} else {
			logger.parserErr(layout.fileFullname, "Cannot get Operator from string: " + line);
			return -1;
		}
		
		// cage size
		str = st.nextToken();
		int cageSize = 0;
		
		try {
			cageSize = Integer.parseInt(str);
		} catch (NumberFormatException e) {
			logger.parserErr(layout.fileFullname, "Cannot get CageSize from string: " + line);
			return -1;
		}
		cage.cageSize = cageSize;
		
		// get all the cells
		if (cageSize != cnt - 3) {
			logger.parserErr(layout.fileFullname, "CageSize and the number of cells mismatch: " + line);
			return -1;
		}
		while (st.hasMoreElements()) {
			str = st.nextToken();
			
			int x = str.charAt(1) - '0';
			int y = str.charAt(0) - 'A' + 1;
			
			if (x < 1 || x > layout.gameSize || y < 1 || y > layout.gameSize) {
				logger.parserErr(layout.fileFullname, "Cell is wrong: " + str + " GameSize: " + layout.gameSize);
				return -1;
			}
			
			Cell cell = new Cell();
			
			// B3 -> Cell(3, 2)
			cell.y = y;
			cell.x = x;
			
			// add the cell to cage
			cell.cage = cage;
			cage.cells.add(cell);
		}
		
		// add cage to layout
		layout.cages.add(cage);

		return 0;
	}
	
	public int fileDataParser(Layout layout) {
		ArrayList<String> strList = layout.txtFileData;
		boolean ifGetName = false;
		boolean ifGetSize = false;
		boolean ifGetEndName = false;
		boolean ifGetCages = false;
		
		for (int i = 0; i < strList.size(); i++) {
			String line = strList.get(i).trim();
			StringTokenizer st = new StringTokenizer(line); 
			int cnt = st.countTokens();
			if (cnt < 1) {		// skip the empty line
				continue;
			}

			// First, try to get the name of the Game, because the name could be "end"
			if (!ifGetName) {
				layout.gameName = line; // name could be more than one words.
				if (cnt > 1) {
					logger.info(layout.fileFullname + " Game name has more than one words");
					// continue..
				}
				ifGetName = true;
				
			} else if (!ifGetSize) {
				try {
					layout.gameSize = Integer.parseInt(line);
				} catch (NumberFormatException e) {
					logger.parserErr(layout.fileFullname, "Cannot get game size from string: " + line);
					return -1;
				}
				if (layout.gameSize < 1 || layout.gameSize > Layout.MAX_GAME_SIZE) {
					logger.parserErr(layout.fileFullname, "Game size (" + layout.gameSize + 
							") should be between 1~6.");
					return -1;
				}
				ifGetSize = true;

			} else if (!ifGetEndName) {
				String str = line.substring(0, 3);				
				if (str.equalsIgnoreCase("end")) {
					if (ifGetName && layout.gameName.equalsIgnoreCase(line.substring(3).trim())) {
						ifGetEndName = true;
						break;	// ignore the left words of the txt file.
					} else {
						logger.parserErr(layout.fileFullname, "name(" + layout.gameName 
								+ ") and end+name(" + line + ") mismatch");
						return -1;
					}						
								
				// analyze the cages
				} else {
					if (cageParser(st, layout, line) != 0) {
						logger.info("cageParser Error");
						return -1;
					}
					ifGetCages = true;
				}
			}
			
			if (ifGetEndName) {
				break;
			}
		}
		
		if (!ifGetName || !ifGetEndName || !ifGetSize || !ifGetCages) {
			logger.parserErr(layout.fileFullname, "Name, endname, size or cages information is missing");
			return -1;
		}
		return 0;
	}
	

}
